package com.sh.caryr.erp.service.impl.order;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.sh.caryr.erp.entity.basis.ExpressComp;
import com.sh.caryr.erp.entity.enums.ProductTypeEnum;
import com.sh.caryr.erp.exception.ResultCode;
import com.sh.caryr.erp.entity.product.ProductSpec;
import com.sh.caryr.erp.entity.trade.Order;
import com.sh.caryr.erp.entity.trade.TradeOrder;
import com.sh.caryr.erp.entity.user.User;
import com.sh.caryr.erp.exception.RestServiceException;
import com.sh.caryr.erp.mapper.order.OrderMapper;
import com.sh.caryr.erp.service.*;
import com.sh.caryr.erp.util.UtilityTool;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private final ITradeOrderService tradeOrderService;

    private final IProductSpecService productSpecService;

    private final IUserService userService;

    @Autowired
    public OrderServiceImpl(ITradeOrderService tradeOrderService, IProductSpecService productSpecService, IUserService userService) {
        this.tradeOrderService = tradeOrderService;
        this.productSpecService = productSpecService;
        this.userService = userService;
    }

    @Override
    public Order getOrderDetailById(Long id) {
        Order order = this.selectById(id);
        if (order == null)
            return null;
        List<TradeOrder> tradeOrderList = tradeOrderService.selectList(
                new EntityWrapper<TradeOrder>().eq("tradeId", id));
        order.setTradeOrderList(tradeOrderList);
        return order;
    }

    @Override
    public List<Order> getOrderDetailByIds(List<Long> ids) {
        List<Order> orders = new ArrayList<>();
        for (Long id : ids)
            orders.add(this.getOrderDetailById(id));
        return orders;
    }

    @Override
    public void getOrderDetail(Order trade) {
        List<TradeOrder> tradeOrderList = tradeOrderService.selectList(
                new EntityWrapper<TradeOrder>().eq("tradeId", trade.getId()));
        for (TradeOrder order : tradeOrderList) {
            ProductSpec spec = productSpecService.selectById(order.getProductSpecId());
            if (spec != null) {
                order.setSalePrice(spec.getSalePrice());
                order.setName(spec.getProductName() + " - " + spec.getName());
            }
        }
        trade.setTradeOrderList(tradeOrderList);

        if (trade.getCreateBy() != null) {
            User user = userService.selectById(trade.getCreateBy());
            if (user != null) {
                trade.setCreatorName(user.getName());
            }
        }

    }

    @Transactional
    @Override
    public void insertOrUpdateOrder(Order order) throws Exception {
        //--- 1.Persist Order
        if (order.getId() == null) {
            this.insert(order);
        } else {
            this.updateById(order);
        }
        // Refresh orderItem
        order.refreshOrderItem();
        //--- 2.Persist orderItem
        tradeOrderService.updateOrderItemByOrder(order);
    }

    @Transactional
    @Override
    public void updateOrderBatch(List<Order> orders) throws Exception {
        if (CollectionUtils.isNotEmpty(orders)) {
            for (Order order : orders) {
                insertOrUpdateOrder(order);
            }
        }
    }

    @Transactional
    @Override
    public void insertOrderSkuAmount(Order trade) {
        //1.新增trade
        this.insert(trade);
        for (TradeOrder order : trade.getTradeOrderList()) {
            order.setTradeId(trade.getId());
            order.setCreateBy(trade.getCreateBy());
            order.setCoco(trade.getCoco());
        }
        //2.新增tradeOrder
        tradeOrderService.insertBatch(trade.getTradeOrderList());
    }


    @Transactional
    @Override
    @SuppressWarnings("unchecked")
    public void deleteOrderById(List<Long> ids) {
        List<Order> orderList = this.selectBatchIds(ids);

        if (orderList == null || orderList.isEmpty()) {
            throw new RestServiceException(ResultCode.DELETE_NOT_FOUND);
        }
        /*for (Order order : orderList) {
            if (order.getStatus() >= OrderStatus.WAIT_ASSGN_EXP.getValue()) { //Not draft trade, cannot delete
                throw new RestServiceException(ResultCode.TRADE_DEL_NOT_ALLOWED_STD);
            }
        }*/

        //Soft delete trade
        try {
            UtilityTool.softDelete(Order.class, ids, this);
            Wrapper wrapper = new EntityWrapper<>();
            wrapper.in("tradeId", ids);
            List<TradeOrder> tradeOrders = tradeOrderService.selectList(wrapper);
            if (tradeOrders != null && !tradeOrders.isEmpty()) {
                List<Long> orderIds = new ArrayList<>();
                for (TradeOrder order : tradeOrders) {
                    orderIds.add(order.getId());
                }
                //Soft delete trade orders
                UtilityTool.softDelete(TradeOrder.class, orderIds, tradeOrderService);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RestServiceException(ResultCode.DELETE_NOT_FOUND);
        }
    }

    @Transactional
    @Override
    public void insertOrdersFromExcel(List<Order> orderList) throws Exception {
        /*List<ExpressComp> expressComps = UtilityTool.getExpressComps();
        //补全信息
        for (Trade trade : tradeList) {
            trade.setReceiveAmount(trade.getPaymentAmount());
            List<TradeOrder> tradeOrderList = trade.getTradeOrderList();
            for (TradeOrder tradeOrder : tradeOrderList) {
                if ("单品".equals(tradeOrder.getProductTypeForExcel())) {
                    tradeOrder.setProductType(ProductTypeEnum.NORMAL);
                } else if ("套件".equals(tradeOrder.getProductTypeForExcel())) {
                    tradeOrder.setProductType(ProductTypeEnum.CONTAINSKU);
                }
                tradeOrder.setCoco(trade.getCoco());
                tradeOrder.setPlantTxnId(trade.getPlantTxnId());
                tradeOrder.setShopId(trade.getShopId());
                tradeOrder.setPayTime(trade.getPayTime());
                tradeOrder.setOrderTime(trade.getOrderTime());
                String expCompCode = UtilityTool.getExpCompCodeByName(expressComps, tradeOrder.getLogisticsName());
                tradeOrder.setLogisticsName(expCompCode);
            }
        }*/

        //创建 or update
        for (Order order : orderList) {
            //this.insertOrderSkuAmount(trade);
            if (order.getId() == null) {
                this.insertOrderSkuAmount(order);
            } else {
                this.compactOrderByProSpec(order);
                this.insertOrUpdateOrder(order);
            }
        }

    }

    public List<Order> getOrderByUpdate(List<Order> tradesFromClient){
        List<Order> orders = new ArrayList<>();

        //Get the old trade list
        List<Long> tradeIds = new ArrayList<>();
        for(Order order : tradesFromClient){
            if(order.getId() !=null){
                tradeIds.add(order.getId());
            }
        }
        Map<Long, Order> tradeMap = new HashMap<>();
        if(!tradeIds.isEmpty()){
            List<Order> orderListOld = this.getOrderDetailByIds(tradeIds);
            for(Order order : orderListOld){
                tradeMap.put(order.getId(), order);
            }
        }

        //Update some values from old trades
        List<ExpressComp> expressComps = UtilityTool.getExpressComps();
        for(Order trade: tradesFromClient){
            if(trade.getId()!=null){
                Order orderOld = tradeMap.get(trade.getId());
                //Update the property from client trade
                orderOld.setReceiver(trade.getReceiver());
                orderOld.setPhoneNum(trade.getPhoneNum());
                orderOld.setAddress(trade.getAddress());
                orderOld.setPostCode(trade.getPostCode());
                orderOld.setCustomRemark(trade.getCustomRemark());
                orderOld.setSystemRemark(trade.getSystemRemark());
                orderOld.setLogisticsAmount(trade.getLogisticsAmount());
                orderOld.setPaymentAmount(trade.getPaymentAmount());
                orderOld.setTradeOrderList(trade.getTradeOrderList());
                trade = orderOld;
            }
            trade.setReceiveAmount(trade.getPaymentAmount());

            for(TradeOrder order : trade.getTradeOrderList()){
                if ("单品".equals(order.getProductTypeForExcel())) {
                    order.setProductType(ProductTypeEnum.NORMAL);
                } else if ("套件".equals(order.getProductTypeForExcel())) {
                    order.setProductType(ProductTypeEnum.CONTAINSKU);
                }
                order.setPlantTxnId(trade.getExtTxnId());
                order.setShopId(trade.getShopId());
                order.setPayTime(trade.getPaymentTime());
                order.setOrderTime(trade.getOrderTime());
                String expCompCode = UtilityTool.getExpCompCodeByName(expressComps, order.getExpressName());
                order.setExpressName(expCompCode);
                ProductSpec spec = productSpecService.selectById(order.getProductSpecId());
                order.setSalePrice(spec != null ? spec.getSalePrice() : null);
            }
            orders.add(trade);
        }
        return orders;
    }

    private void compactOrderByProSpec(Order trade) {
        List<TradeOrder> newOrders = trade.getTradeOrderList();
        List<TradeOrder> oldOrders = tradeOrderService.selectList(
                new EntityWrapper<TradeOrder>().eq("tradeId", trade.getId()));

        if (newOrders == null || oldOrders.isEmpty()) {
            return ;
        }

        Map<String, TradeOrder> orderMap = new HashMap<>();
        List<TradeOrder> orders = new ArrayList<>();
        //Convert oldOrder list to map.
        for (TradeOrder order : oldOrders) {
            String key = getOrderIdentity(order);
            orderMap.put(key, order);
        }
        //Check the newOrders
        for (TradeOrder order : newOrders) {
            String key = getOrderIdentity(order);
            TradeOrder oldOrder = orderMap.get(key);
            if (oldOrder != null) {
                oldOrder.setExpressOrderId(order.getExpressOrderId());
                oldOrder.setExpressName(order.getExpressName());
                orders.add(oldOrder);
            }else{
                orders.add(order);
            }
        }
        trade.setTradeOrderList(orders);
    }

    private String getOrderIdentity(TradeOrder order) {
        return order.getProductSpecId() + "-" + order.getProductSpecAmount();
    }
}
